home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 8: LINUX Games
/
Linux Cubed Series 8 - LINUX Games.iso
/
games
/
x11
/
networke
/
civ-0.000
/
civ-0
/
civ-0.3
/
src
/
city.cc.orig
< prev
next >
Wrap
Text File
|
1995-11-19
|
12KB
|
468 lines
#include <string.h>
#include "misc.h"
#include "defs.h"
#include "graph.h"
#include "city.h"
#include "world.h"
#include "rivers.h"
#include "MsgQ.h"
#include "player.h"
#include "units.h"
#include "trans.h"
#include "display.h"
#include "move.h"
#include "rules.h"
#include "hash.h"
#include "savefile.h"
#ifdef FOR_X11
#include <sys/types.h>
#include <netinet/in.h>
#else
#include <winsock.h>
#endif
// pixmaps
#include "../pic/bulb.xpm"
#include "../pic/elvis.xpm"
#include "../pic/food.xpm"
#include "../pic/goonda.xpm"
#include "../pic/lux.xpm"
#include "../pic/money.xpm"
#include "../pic/shield.xpm"
#include "../pic/trade.xpm"
#include "../pic/worker.xpm"
#include "../pic/city.xpm"
const char *backGroundColor = "#79e78e38ffff";
int City::white, City::black, City::back, City::red, City::gray;
long City::hBulb, City::hElvis, City::hFood;
long City::hGoonda, City::hLux, City::hMoney;
long City::hShield, City::hTrade, City::hWorker;
City::City(char *Name, ulong Id, int X, int Y, uchar OwnerId)
{
name = Name;
x = X;
y = Y;
id = Id;
trans->SetPtr(id, this);
ownerId = OwnerId;
players[ownerId]->citys.Insert(id);
size = 1;
building = "Settlers";
accProd = 0;
needProd = buildObjects.Find(StrKey(building))->prodCost;
foodSupport = foodStored = 0;
foodStoreCap = 20;
world->WhichCity(x,y) = id;
if (ownerId == playerId) world->SeeSquare(x, y, 1);
world->Working(x, y) = id;
DrawIfVisible();
PutExtraWorker();
if (ownerId == playerId)
ComputeEcon();
}
// read from save file
City::City()
{
id = ReadULong();
name = ReadString();
x = ReadUShort();
y = ReadUShort();
ownerId = ReadUChar();
size = ReadUChar();
building = LookupBuilding(ReadString(), 0);
accProd = ReadUShort();
needProd = ReadUShort();
foodStored = ReadUShort();
foodSupport = ReadUShort();
foodStoreCap = ReadUShort();
int n = ReadUShort();
for (;n > 0; --n)
buildings.Insert(LookupBuilding(ReadString(), 0));
trans->SetPtr(id, this);
players[ownerId]->citys.Insert(id);
world->WhichCity(x, y) = id;
}
City::~City()
{
for (int xi = 0; xi < 5; ++xi) for (int yi = 0; yi < 5; ++yi) {
if ((xi % 4) == 0 && (yi % 4) == 0) continue;
int x1 = world->FixX(x+xi-2), y1 = world->FixY(y+yi-2);
if (world->Working(x1, y1) == id)
world->Working(x1, y1) = 0;
}
while (buildings) {
char *name = buildings.RemoveHead();
players[ownerId]->DeleteWonder(name);
}
world->WhichCity(x,y) = 0;
players[ownerId]->citys.Delete(id);
delete name;
DrawIfVisible();
if (id == playerId)
world->HideSquare(x, y, 2);
}
char *City::LookupBuilding(char *str, int insertWonder)
{
BuildObject *obj = buildObjects.Find(StrKey(str));
delete str;
if (obj == NULL)
return NULL;
if (insertWonder && obj->wonder) {
players[ownerId]->wonders.Insert(obj->name);
obj->built = 1;
}
return obj->name;
}
void City::DeleteBuilding(char *name)
{
for (Lister<charp> l = buildings; l; l.Next())
if (strcmp(l.Elem(), name) == 0) {
l.Delete();
return;
}
}
void City::Draw(int atx, int aty)
{
if (players[ownerId]->cityPic == 0)
players[ownerId]->cityPic = players[ownerId]->CompilePic(city_xpm);
screen->DrawPixmap(atx, aty, players[ownerId]->cityPic);
if (size < 10)
screen->WriteInt(atx+4, aty+4, size, 1, black);
else
screen->WriteInt(atx, aty, size, 2, black);
if (HasBuilding("City Walls")) {
int w, h;
screen->GetPixmapInfo(players[ownerId]->cityPic, w, h);
screen->Rect(atx+1, aty+1, w-2, h-2, gray);
screen->Rect(atx, aty, w, h, gray);
}
}
void City::DrawIfVisible()
{
if (!world->Visible(x, y) || !display->Visible(x, y)) return;
int sx, sy;
display->TranslateScreen(x, y, sx, sy);
world->Draw(x, y, 1, 1, sx, sy);
}
void AllocCityColors()
{
City::white = screen->AllocColor("#ffffffffffff");
City::red = screen->AllocColor("red");
City::black = screen->AllocColor("#000000000000");
City::back = screen->AllocColor((char *)backGroundColor);
City::gray = screen->AllocColor("SlateGray");
City::hBulb = screen->CompilePixmap(bulb_xpm);
City::hElvis = screen->CompilePixmap(elvis_xpm);
City::hFood = screen->CompilePixmap(food_xpm);
City::hGoonda = screen->CompilePixmap(goonda_xpm);
City::hLux = screen->CompilePixmap(lux_xpm);
City::hMoney = screen->CompilePixmap(money_xpm);
City::hShield = screen->CompilePixmap(shield_xpm);
City::hTrade = screen->CompilePixmap(trade_xpm);
City::hWorker = screen->CompilePixmap(worker_xpm);
}
// find an empty spot and put work on it
void City::PutExtraWorker()
{
int mx, my, f = -1, p = -1, t = -1;
for (int xi = 0; xi < 5; ++xi) for (int yi = 0; yi < 5; ++yi) {
if ((xi % 4) == 0 && (yi % 4) == 0) continue;
int x1 = world->FixX(x+xi-2), y1 = world->FixY(y+yi-2);
if (world->RealVisible(x1, y1) == 0) continue;
if (world->Working(x1, y1) != 0) continue;
int cf = world->Food(x1, y1, ownerId);
int cp = world->Prod(x1, y1, ownerId);
int ct = world->Trade(x1, y1, ownerId);
if (cf > f || (cf == f && (ct > t || (ct == t && cp > p)))) {
f = cf; p = cp; t = ct;
mx = x1; my = y1;
}
}
if (f != -1)
world->Working(mx, my) = id;
}
// find a spot and pollute it
void City::PutPollution()
{
int f = 0;
// first check that there is a spot not already polluted
for (int xi = 0; xi < 5; ++xi) for (int yi = 0; yi < 5; ++yi) {
if ((xi % 4) == 0 && (yi % 4) == 0) continue;
int x1 = world->FixX(x+xi-2), y1 = world->FixY(y+yi-2);
if ((x1 != x || y1 != y) && !world->Polluted(x1, y1)) {
f = 1;
}
}
// if there are any spots unpolluted, roll randomly until we pick one
while (f) {
int xi, yi;
xi = random() % 5;
yi = random() % 5;
if ((xi % 4) == 0 && (yi % 4) == 0) continue;
int x1 = world->FixX(x+(xi)-2);
int y1 = world->FixX(y+(yi)-2);
if ((x1 != x || y1 != y) && !world->Polluted(x1,y1)) {
world->Pollute(x1,y1);
f = 0;
}
}
}
void City::ComputeEcon()
{
Debug('c', "Computing economy for city %s\n", name);
prod = food = trade = pollution = working = 0;
for (int xi = 0; xi < 5; ++xi) for (int yi = 0; yi < 5; ++yi) {
if ((xi % 4) == 0 && (yi % 4) == 0) continue;
int x1 = world->FixX(x+xi-2), y1 = world->FixY(y+yi-2);
if (world->Working(x1, y1) != id) continue;
ulong enemyUnit = 0;
for (Lister<ulong> unitl = world->Units(x1, y1); unitl; unitl.Next())
if (trans->TransUnit(unitl.Elem())->ownerId != ownerId)
enemyUnit = unitl.Elem();
if (enemyUnit != 0) {
world->Working(x1, y1) = 0; // can't work here
continue;
}
if (working == size && !(x1 == x && y1 == y)) {
world->Working(x1, y1) = 0;
continue;
}
food += world->Food(x1, y1, ownerId);
prod += world->Prod(x1, y1, ownerId);
int val = world->Trade(x1, y1, ownerId);
if (val > 0) val += players[ownerId]->tradeBonus;
trade += val;
if (!(x1 == x && y1 == y)) ++working;
}
Player *p = players[ownerId];
elvi = size-working;
money = trade*p->tax/100;
luxuries = trade*p->luxuries/100;
science = trade-money-luxuries;
luxuries += 2*elvi;
goondas = size - FREE_CONTENTED;
if (goondas < 0) goondas = 0;
happy = 0;
food -= 2*size;
food -= foodSupport;
p->WonderEffect(this);
if (p->govt < REPUBLIC) // martial order
goondas -= world->Units(x, y).Count();
int transit=0, factory=0, mfg=0, plant=0, recycling=0, dirtyplant= 0;
for (Lister<charp> l = buildings; l; l.Next()) {
BuildObject *obj = buildObjects.Find(StrKey(l.Elem()));
switch (obj->type) {
case BANK:
luxuries = int(luxuries*1.5);
money = int(money*1.5);
break;
case CATHEDRAL:
goondas -= p->cathedralEffect;
break;
case COLOSSEUM:
goondas -= 3;
break;
case POWERPLANT:
dirtyplant = 1;
// no break
case HYDROPLANT:
// no break
case FUSIONPLANT:
// no break
case NUCLEARPLANT:
plant = 1;
break;
case FACTORY:
factory = 1;
break;
case MFGPLANT:
mfg = 1;
break;
case LIBRARY:
science = int(science*1.5);
break;
case MARKETPLACE:
luxuries = int(luxuries*1.5);
money = int(money*1.5);
break;
case RECYCLINGCTR:
recycling = 1;
break;
case TEMPLE:
goondas = goondas-p->templeEffect;
break;
case UNIVERSITY:
if (p->HasWonder("Isaac Newton's College"))
science = science*2;
else
science = int(science*1.5);
}
}
if (p->HasWonder("Hoover Dam")) {
plant = 1;
}
if (mfg) {
prod = prod*2;
}
else if (factory) {
prod = int(prod*1.5);
}
if (plant && (mfg || factory)) {
prod = int(prod*1.5);
}
if (!transit) {
if (Discovered(ownerId,"Automobile")) {
pollution += size;
}
else {
if (size > 10) {
pollution += size - 10;
}
}
}
if (dirtyplant) {
if (recycling) {
pollution += prod/2;
}
else {
pollution += prod;
}
}
// SETI program
if (p->HasWonder("SETI Program"))
science = int(science*1.5);
// each 2 luxuries reduces goondas by one,
// when run out of goondas actually create happy instead:
if (goondas<0) goondas = 0;
goondas -= int(luxuries/2);
if (goondas < 0) {
happy-= goondas;
goondas = 0;
}
// prod, money and science zeroed if goondas > happy:
if (goondas > happy) {
prod = 0;
money = 0;
science = 0;
}
int support = units.Count();
if (p->govt <= DESPOT) support -= size;
if (support < 0) support = 0;
surpProd = prod-support;
}
int City::Update()
{
// size zero = city dies:
if (size <= 0) return 0;
ComputeEcon();
Debug('c', "Updating city %s\n", name);
while (surpProd < 0) { // kill a unit
Unit *unit = trans->TransUnit(units.RemoveHead());
AddMessage(messages, "%s can't support %s", name, names[unit->Type()]);
*moveQ << PieceMove(unit->id, PIECE_DIE, 0, 0);
if (unit->type == SETTLER)
++food;
delete unit;
++surpProd;
}
accProd += surpProd;
foodStored += food;
if (foodStored < 0) { // kill off settlers
for (Lister<ulong> unitl = units; unitl && foodStored < 0;) {
Unit *unit = trans->TransUnit(unitl.Elem());
if (unit->type == SETTLER) {
AddMessage(messages, "%s can't feed Settlers", name);
*moveQ << PieceMove(unit->id, PIECE_DIE, 0, 0);
delete unit;
unitl = units;
++foodStored;
}
else
unitl.Next();
}
}
if (foodStored < 0) {
foodStored = 0;
--size;
foodStoreCap -= 10;
AddMessage(messages, "Famine in %s, population decrease", name);
if (size <= 0) // city dies
return 0;
else
*moveQ << PieceMove(id, CITY_SIZE, size, 0);
DrawIfVisible();
}
if (foodStored >= foodStoreCap) { // eat food, maybe grow city
// check for granary to retain half of foodStored:
if (HasBuilding("Granary")) foodStored -= (int) foodStoreCap/2;
else foodStored -= foodStoreCap;
// cannot pass size 10 without aquaduct
if ((size >= 10) && !HasBuilding("Aquaduct")) {
AddMessage(messages, "%s needs aquaduct to grow", name);
} else {
++size;
*moveQ << PieceMove(id, CITY_SIZE, size, 0);
foodStoreCap += 10;
PutExtraWorker();
DrawIfVisible();
}
}
if (building != NULL && accProd >= needProd) {
Produce();
}
ComputeEcon();
if (random() % 100 +1 <= pollution) {
PutPollution();
}
// notification of civil disorder:
// also, collapse of democracy into anarchy if any city does civil-disorder.
if (goondas > happy) {
AddMessage(messages, "Civil disorder in %s", name);
if (players[ownerId]->govt == DEMOCRACY)
players[ownerId]->govt = ANARCHY;
}
players[ownerId]->money += money;
players[ownerId]->scienceAcc += science;
for (Lister<charp> l = buildings; l;) {
BuildObject *obj = buildObjects.Find(StrKey(l.Elem()));
players[ownerId]->money -= obj->maint;
if (players[ownerId]->money < 0) {
players[ownerId]->money += obj->prodCost;
AddMessage(messages, "%s can't maintain %s", name, l.Elem());
l.Delete();
if (strcmp(obj->name,"City Walls")==0)
*moveQ << PieceMove(id,CITY_WALL,0,0);
else players[ownerId]->DeleteWonder(obj->name);
}
else
l.Next();
}
Debug('c', "Done updating city %s\n", name);
return 1;
}